local _M = {}

function _M.new()
    local bus = {}

    local callbacks = {}

    --- subscribe one message type.
    --
    -- Register an subject callback function handler.
    -- subject: the string type subject name
    -- handler: the subject callback function handler
    -- index: the index to insert the handler (1 is the highest priority)
    bus.subscribe = function (subject, cb, index)
        if not subject then 
            error('Invalid subject name')
        end
        if type(cb) ~= 'function' then
            error('Invalid subject handler')
        end

        if not callbacks[subject] then
            callbacks[subject] = {}
        end
        bus.unsubscribe(subject, cb)
        table.insert(callbacks[subject], index or #callbacks[subject] + 1, cb)
    end

    --- unsubscribe one message type.
    --
    -- Remove a registered subject callback function handler.
    -- subject: the string type subject name
    -- handler: the subject callback function handler to unsubscribe
    bus.unsubscribe = function (subject, cb)
        local h = callbacks[subject]
        if not h then
            return
        end

        for i = 1, #h do
            if h[i] == cb then
                table.remove(h, i)
            end
        end
    end

    --- Generate subject.
    --
    -- call all subject callback function in the order they were registered.
    -- Passes all arguments to the callback function.
    --
    -- subject: the string type subject name
    -- ...: the remaining paramters are passed on to the handler
    bus.publish = function (subject, ...)
        local cbs = callbacks[subject]
        if not callbacks then
            return
        end
        for i = 1, #cbs do
            cbs[i](...)
        end
    end

    return bus
end

return _M
